package org.zxp.javacheck.stringtest;

import org.junit.Test;

import java.lang.ref.WeakReference;

/**
 * @program: effectiveJava
 * @description: 测试字符串相关类，为什么"abc"是强引用
 * @author: X-Pacific zhang
 * @create: 2019-05-21 14:12
 **/
public class StringTest {
    public static void main(String[] args) {
//        String str1 = new String("abc");
//        String str2 = new String("abc");
//        String str3 = "abc";
//        String str4 = "abc";
//        System.out.println(str1 == str3);//false
//        System.out.println(str1 == str2);//false
//        System.out.println(str3 == str4);//true

        //JDK7以前
//        String str1 = new String("abc");  "abc"本体分别存在于常量池和堆中，str1是指向堆中的“abc”的引用（返回到方法栈中）
//        String str3 = "abc"; "abc"本体常量池中，str3是指向常量池中的“abc”的引用，常量池中只能有一份"abc"
//        str1是堆中"abc"本体的引用，str3是常量池中"abc"本体的引用，所以str1与str3肯定不相等
//        JDK7以后 常量池从方法区移动到堆中 常量池会直接存堆中的引用（GC很少光顾原来常量池所在的方法区），堆中保存字符串本体
//        String str1 = new String("abc");  "abc"本体保存在于堆中，常量池保存堆中"abc"的引用，new String又保存一个"abc"的本体 str1是指向堆中"第二个本体的引用
//        String str3 = "abc"; 常量池中有了"abc"的引用，就是1号本体的引用
//        为什么"abc"是强引用，abc一直被字符串常量池所引用，而new String则是堆中新创建的对象
        WeakReference<String> weakReference1 = new WeakReference<>(new String("abc"));
        WeakReference<String> weakReference2 = new WeakReference<>("abc");
        try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(weakReference1.get());//abc
        System.out.println(weakReference2.get());//abc
        /**
         * 在垃圾回收器线程扫描它所管辖的内存区域的过程中，一旦发现了只具有弱引用的对象，
         * 不管当前内存空间足够与否，都会回收它的内存。不过，
         * 由于垃圾回收器是一个优先级很低的线程，因此不一定会很快发现那些只具有弱引用的对象。
         */
        System.gc();//遇到gc就回收了
        System.out.println(weakReference1.get());//null
        System.out.println(weakReference2.get());//abc
    }



}
